package edu.chalmers.targine;

import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.opengl.GLUtils;
import edu.dhbw.andar.ARObject;

public abstract class Arbject extends ARObject{
    public boolean hasModel = false;
	public boolean dirty = false;
	protected boolean resetModels = false;
	
	private String name;
	private String patternID;
	private String nfcID;
	protected String value;
	private double markerWidth;
	private double[] center;
	
	protected ArrayList<Mesh> newMeshes = new ArrayList<Mesh>();
	protected ArrayList<Mesh> meshes = new ArrayList<Mesh>();
	protected ArrayList<Billboard> billboards = new ArrayList<Billboard>();
	protected ArrayList<TextBillboard> textBillboards = new ArrayList<TextBillboard>();
	
	protected Context mContext;
	
	public Arbject(String name, String patternID, String nfcID, Context context) {
		super(name, patternID, 80, new double[]{0,0});
		this.name = name;
		this.patternID = patternID;
		this.nfcID = nfcID;
		this.markerWidth = 80;
		this.center = new double[]{0,0};
		mContext = context;
		
		value = "none";
	}
	
	@Override
	public void init(GL10 gl){
		if(resetModels){
			clear();
		}
		
		synchronized(newMeshes){
			if(!newMeshes.isEmpty()){
				meshes.addAll(newMeshes);
				newMeshes = new ArrayList<Mesh>();
			}
		}
		
		for(Mesh mesh : meshes){
			mesh.init(gl);
		}
		
		for(TextBillboard tb: textBillboards){
			if(tb.isUninitialised()){
				tb.init(gl);
			}
		}
	}

	@Override
	public synchronized void draw(GL10 gl){
		super.draw(gl);
		
		for(Mesh mesh : meshes){
			if(mesh.isFinalized() && mesh.hasModel()){
				mesh.draw(gl);
			}
		}
		
		for(Mesh mesh: meshes){
			mesh.update();
		}
		
		for(Billboard bb : billboards){
			bb.draw(gl);
		}
		
		for(TextBillboard tb : textBillboards){
			tb.draw(gl);
		}
	}
	
	// Will load a texture out of a drawable resource file, and return an OpenGL texture ID:
	protected int loadTexture(GL10 gl, Context context, int resource) {
	    // In which ID will we be storing this texture?
		int[] tempTex = new int[1];
		gl.glGenTextures(1, tempTex, 0);
	    int id = tempTex[0];
	    
	    // We need to flip the textures vertically:
	    Matrix flip = new Matrix();
	    flip.postScale(1f, -1f);
	    
	    // This will tell the BitmapFactory to not scale based on the device's pixel density:
	    // (Thanks to Matthew Marshall for this bit)
	    BitmapFactory.Options opts = new BitmapFactory.Options();
	    opts.inScaled = false;
	    
	    // Load up, and flip the texture:
	    Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts);
	    Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
	    temp.recycle();
	    
	    gl.glBindTexture(GL10.GL_TEXTURE_2D, id);
	    
	    // Set all of our texture parameters:
	    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
	    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
	    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
	    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
	    
	    // Generate, and load up all of the mipmaps:
	    for(int level=0, height = bmp.getHeight(), width = bmp.getWidth(); true; level++) {
	        // Push the bitmap onto the GPU:
	        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bmp, 0);
	        
	        // We need to stop when the texture is 1x1:
	        if(height==1 && width==1) break;
	        
	        // Resize, and let's go again:
	        width >>= 1; height >>= 1;
	        if(width<1)  width = 1;
	        if(height<1) height = 1;
	        
	        Bitmap bmp2 = Bitmap.createScaledBitmap(bmp, width, height, true);
	        bmp.recycle();
	        bmp = bmp2;
	    }
	    
	    bmp.recycle();
	    
	    return id;
	}
	
	public void markForReset(){
		resetModels = true;
		markForReinitialization();
	}
	
	public void clear(){
		value = "none";
		hasModel = false;
		meshes.clear();
		billboards.clear();
		textBillboards.clear();
		resetModels = false;
	}
	
	public void addBillboard(int texID, float x, float y, float z, float scale, float xRot){
		billboards.add(new Billboard(texID, x, y, z, scale, xRot));
	}
	
	public void addTextBillboard(TextBillboard textBillboard){
		textBillboards.add(textBillboard);
	}
	
	public void addMesh(Mesh mesh){
		newMeshes.add(mesh);
		markForReinitialization();
	}
	
	public String getName(){
		return name;
	}
	
	public String getPatternID(){
		return patternID;
	}
	
	public String getID(){
		return nfcID;
	}
	
	public double getMarkerWidth(){
		return markerWidth;
	}
	
	public double[] getCenter(){
		return center;
	}
	
	public String getValue(){
		return value;
	}
}
